package crack

import (
	"crypto/aes"
	"crypto/cipher"
	"encoding/base64"
	"encoding/binary"
	"encoding/hex"
	"net"
	"strconv"
	"strings"
	"time"
)

var (
	key = "0123456789abcdef"
	a   = "U+0047U+0038U+006FU+002BU+006BU+0064U+002FU+0034U+0079U+0038U+0063U+0068U+0050U+0043U+0061U+004FU+0062U+004BU+004BU+0038U+004CU+0039U+002BU+0074U+004AU+0056U+0046U+0042U+0062U+0037U+006EU+0074U+0057U+0048U+002FU+0045U+0058U+004AU+0037U+0034U+0036U+0033U+0035U+0056U+0033U+0055U+0054U+0058U+0041U+0034U+0054U+0046U+004FU+0063U+0036U+0075U+0061U+0062U+005AU+0066U+0075U+004CU+0072U+0030U+0058U+0069U+0073U+006EU+006BU+0037U+004FU+0073U+004BU+004AU+005AU+0032U+0058U+0064U+0064U+0033U+006CU+0038U+0048U+004EU+004CU+0064U+004DU+004FU+0059U+005AU+0058U+0041U+0058U+0035U+005AU+0058U+006EU+004DU+0043U+0034U+0071U+0049U+002BU+0031U+0064U+002FU+004DU+0058U+0041U+0032U+0054U+006DU+0069U+0064U+0058U+0065U+0071U+0047U+0074U+0038U+0064U+0039U+0055U+0045U+0046U+0035U+0056U+0065U+0073U+0051U+006CU+0068U+0050U+0030U+0035U+0031U+0047U+0047U+0042U+0053U+006CU+0064U+006BU+004AU+006BU+0056U+0072U+0050U+002FU+0066U+007AU+006EU+0034U+0067U+0076U+004CU+0058U+0063U+0077U+0067U+0041U+0059U+0065U+0065U+0033U+005AU+0069U+0032U+006FU+0070U+0041U+0076U+0075U+004DU+0036U+0053U+0063U+0058U+0072U+004DU+006BU+0063U+0062U+0078U+0032U+0030U+0030U+0054U+0068U+006EU+004FU+004FU+0045U+0078U+0039U+0038U+002FU+0037U+0041U+0072U+0074U+0065U+006FU+0072U+006EU+0062U+0052U+0069U+0058U+0051U+006AU+006EU+0072U+0036U+0064U+006BU+004AU+0045U+0055U+0044U+0054U+0053U+0034U+0033U+0041U+0057U+0036U+004AU+006CU+0033U+004FU+004BU+0032U+0038U+0037U+0036U+0059U+0061U+007AU+0035U+0069U+0059U+0042U+0078U+002BU+0044U+0057U+0035U+0057U+006AU+0069U+004CU+0063U+004DU+0052U+002BU+0062U+0035U+0038U+004EU+004AU+0052U+0078U+006DU+0034U+0046U+006CU+0056U+0070U+0075U+0073U+005AU+006AU+0042U+0070U+007AU+0045U+0073U+0034U+0058U+004FU+0045U+0071U+0067U+006CU+006BU+0036U+0051U+0049U+0057U+0066U+0057U+0062U+0046U+005AU+0059U+0067U+0064U+004EU+004CU+0079U+0033U+0057U+0061U+0046U+006BU+006BU+0067U+0044U+006AU+006DU+0042U+0031U+002BU+0036U+004CU+0068U+0070U+0059U+0053U+004FU+0061U+0054U+0073U+0068U+0034U+0045U+004DU+0030U+0072U+0077U+005AU+0071U+0032U+005AU+0034U+004CU+0072U+0038U+0054U+0045U+0035U+0057U+0063U+0050U+006BU+0062U+002FU+004AU+004EU+0073U+0057U+004EU+0062U+0069U+0062U+004BU+006CU+0077U+0074U+004EU+0074U+0070U+0039U+0034U+0066U+0049U+0059U+0076U+0041U+0057U+0067U+0078U+0074U+0035U+006DU+006EU+002FU+006FU+0058U+0070U+0066U+0055U+0044"
	b   = "U+0035U+0032U+0048U+0065U+0043U+0051U+0045U+0062U+0073U+0053U+0077U+0069U+0053U+0058U+0067U+0039U+0038U+0073U+0064U+0044U+0036U+0034U+0071U+0079U+0052U+006FU+0075U+0030U+006AU+0041U+0052U+006CU+0076U+0066U+0051U+0069U+0031U+0065U+006BU+0044U+0048U+0053U+0037U+0037U+004EU+006BU+002FU+0038U+0064U+0059U+0066U+0074U+004EU+0058U+006CU+0046U+0061U+0068U+004CU+0045U+0059U+0057U+0049U+0078U+0059U+0059U+004AU+0038U+0075U+0035U+0033U+0064U+0062U+0039U+004FU+0061U+0044U+0066U+0041U+0076U+004FU+0045U+006BU+0075U+006FU+0078U+002BU+0070U+002BU+0049U+0063U+0031U+0056U+004CU+0037U+0030U+0072U+0039U+0051U+0035U+0048U+0075U+004CU+002BU+004EU+004DU+0079U+0065U+0079U+0065U+004EU+0035U+0054U+0035U+0065U+006CU+0030U+0037U+0058U+0035U+0063U+0054U+0036U+0036U+006FU+0042U+0044U+004AU+006EU+0053U+0063U+0073U+0031U+0058U+0064U+0076U+004DU+0036U+0043U+0042U+0052U+0074U+006AU+0031U+006BU+0055U+0073U+0032U+0068U+0034U+0030U+005AU+0035U+0056U+006AU+0039U+0045U+0047U+007AU+0047U+006BU+0039U+0039U+0053U+0046U+0058U+006AU+0053U+0071U+0062U+0074U+0047U+0066U+004BU+0046U+0042U+0070U+0030U+0044U+0068U+004CU+0035U+0077U+0050U+0051U+004BU+0073U+006FU+0069U+0058U+0059U+004CU+004BU+004BU+0068U+0039U+004EU+0051U+0069U+004FU+0068U+004FU+004DU+0057U+0048U+0059U+0079U+002FU+0043U+002BU+0049U+0077U+0068U+0066U+0033U+0051U+0072U+0038U+0064U+0031U+0057U+0062U+0073U+0032U+0076U+0067U+0045U+007AU+0061U+0057U+005AU+0071U+0049U+004AU+0033U+0042U+004DU+0033U+007AU+002BU+0064U+0068U+0052U+0042U+0073U+007AU+0051U+006FU+0051U+0066U+0074U+0073U+007AU+0043U+0031U+0036U+0054U+0055U+0068U+0047U+0051U+0063U+0034U+0038U+0058U+0050U+0046U+0048U+004EU+0037U+0034U+0056U+0052U+0078U+0058U+0067U+0056U+0065U+0036U+0078U+004EU+0051U+0077U+0071U+0072U+0057U+0045U+0070U+0041U+0034U+0068U+0063U+0051U+0065U+0046U+0031U+002BU+0051U+0071U+0052U+0056U+0048U+0078U+0075U+004EU+002BU+0050U+0046U+0052U+0037U+0071U+0077U+0045U+0063U+0055U+0031U+004AU+0062U+006EU+0054U+004EU+0049U+0053U+0061U+0053U+0072U+0071U+0045U+0065U+0038U+0047U+0074U+0052U+006FU+0031U+0072U+0032U+0072U+0073U+0037U+002BU+006CU+004FU+0046U+006DU+0062U+0065U+0034U+0071U+0071U+0079U+0055U+004DU+0067U+0048U+0068U+005AU+0036U+0050U+0077U+0075U+0031U+0062U+006BU+0068U+0072U+006FU+0063U+004DU+0055U+0055U+007AU+0057U+0051U+0042U+006FU+0067U+0041U+0076U+0058U+0077U+0046U+0062U+0038"
	c   = "U+002BU+0062U+002FU+006CU+0052U+0063U+006DU+004CU+007AU+0048U+0030U+0063U+0030U+0042U+0059U+0068U+0069U+0054U+0061U+0059U+004EU+0076U+0054U+0056U+0064U+0059U+007AU+0031U+004FU+0064U+0059U+0059U+0044U+004BU+0068U+007AU+0047U+006EU+002FU+0033U+0054U+0033U+0050U+0034U+0062U+0036U+0070U+0041U+0052U+0038U+0044U+002BU+0078U+0050U+0064U+006CU+0062U+0037U+004FU+0034U+0044U+0034U+0041U+0039U+004BU+004DU+0079U+0065U+0049U+0042U+0070U+0068U+0044U+0050U+006DU+0045U+0074U+0046U+0079U+0034U+0034U+0072U+0074U+0074U+006FU+0032U+0064U+0061U+0064U+0046U+006FU+0069U+0074U+0033U+0035U+0030U+006EU+0067U+0068U+0065U+0062U+0078U+0062U+0059U+0041U+0030U+0070U+0054U+0043U+0057U+0049U+0042U+0064U+0031U+006BU+004EU+0030U+0042U+0047U+004DU+0045U+0069U+0064U+0052U+0044U+0042U+0077U+004CU+004FU+0070U+005AU+0045U+0036U+0051U+0070U+0070U+0068U+002FU+0044U+006CU+007AU+0069U+0044U+006AU+006AU+0066U+0058U+0055U+007AU+0039U+0035U+0035U+0064U+0072U+0030U+0063U+0069U+0067U+0063U+0039U+0045U+0054U+0048U+0044U+002FU+002BU+0066U+0033U+0066U+0045U+004CU+004BU+0073U+006FU+0070U+0054U+0050U+006BU+0062U+0043U+0073U+0075U+0064U+0067U+0043U+0073U+0034U+0038U+006DU+006CU+0062U+0058U+0063U+004CU+0031U+0033U+0047U+0056U+0047U+0035U+0063U+0047U+0077U+004BU+007AU+0052U+0075U+0050U+0034U+0065U+007AU+0063U+0064U+004BU+0062U+0059U+007AU+0071U+0031U+0044U+0058U+0032U+0049U+0037U+0052U+004EU+0065U+0042U+0074U+0077U+002FU+0076U+0041U+006CU+0059U+0068U+0036U+0065U+0074U+004BU+004CU+0076U+0037U+0073U+002BU+0059U+0079U+005AU+002FU+0072U+0038U+006DU+0030U+0066U+0042U+0059U+0039U+0041U+0035U+0037U+006AU+002BU+0058U+0072U+0073U+006DU+005AU+0041U+0079U+0054U+0057U+0062U+0068U+0050U+004AU+006BU+0043U+0067U+003DU+003D"
	d   = "U+006BU+002FU+0052U+0047U+0069U+0055U+0051U+002FU+0074U+0077U+0031U+0079U+0069U+0071U+0069U+006FU+0055U+0049U+0071U+0069U+0072U+007AU+0047U+0043U+0031U+0053U+0078U+0054U+0041U+006DU+0051U+006DU+0074U+006EU+0066U+004BU+0064U+0031U+0071U+0069U+004CU+0069U+0073U+0068U+0037U+0046U+0051U+0059U+0078U+0076U+0045U+002BU+0068U+0034U+002FU+0070U+0037U+0052U+004BU+0067U+0057U+0065U+006DU+0049U+0057U+0052U+0058U+0044U+0066U+0032U+0058U+0053U+004AU+0033U+004BU+0030U+004CU+0055U+0049U+0058U+0030U+0076U+0076U+0031U+0067U+0078U+0032U+0065U+0062U+0034U+004EU+0061U+0074U+0055U+0037U+0051U+006FU+0073U+006EU+0072U+0068U+0065U+0062U+007AU+0033U+0067U+0055U+006FU+0037U+0075U+0032U+0035U+0050U+0035U+0042U+005AU+0048U+0031U+0051U+004BU+0064U+0061U+0067U+007AU+0050U+0071U+0074U+0069U+0074U+0056U+006AU+0041U+0053U+0070U+0078U+0049U+006AU+0042U+0033U+0075U+004EU+0057U+0074U+0059U+004DU+0072U+0058U+0047U+006BU+006BU+0075U+0041U+006DU+0038U+0051U+0045U+0069U+0074U+0062U+0065U+0072U+0063U+002BU+006DU+0050U+0030U+0076U+006EU+007AU+005AU+0038U+004EU+0076U+002FU+0078U+0069U+0069U+0047U+0042U+006BU+006FU+0038U+004FU+0034U+0050U+002FU+0077U+0043U+004BU+0061U+004EU+0032U+004BU+005AU+0056U+0044U+004CU+0062U+0076U+0032U+006AU+0072U+004EU+0038U+0056U+002FU+0031U+007AU+0059U+0036U+0066U+0076U+0057U+0041U+003DU+003D"
	//e    = "U+004AU+0071U+004EU+0077U+0036U+0050U+0055U+004BU+0063U+0057U+004FU+0059U+0046U+0069U+0073U+0055U+006FU+0055U+0043U+0079U+0044U+0032U+0034U+0077U+006EU+004DU+004CU+0032U+0059U+0064U+0038U+006BU+0075U+006DU+0078U+0039U+0068U+004AU+006EU+0046U+0057U+0062U+0068U+004DU+0032U+0054U+0051U+006BU+0052U+0076U+004BU+0048U+0073U+004FU+004DU+0057U+007AU+0050U+0056U+0066U+0067U+0067U+0052U+0072U+004CU+006CU+0038U+0073U+004CU+0051U+0046U+0071U+007AU+006BU+0038U+0062U+0076U+0038U+0052U+0070U+006FU+0078U+0033U+0075U+0053U+0036U+0031U+006CU+0034U+0038U+0030U+004DU+0076U+0037U+0048U+0064U+0042U+0050U+0065U+0042U+0065U+0042U+0065U+0046U+0075U+0064U+005AU+004DU+006EU+0074U+0058U+0042U+0055U+0061U+0034U+0070U+0057U+0055U+0048U+0038U+0044U+0039U+0045U+0058U+0043U+006AU+006FU+0055U+0071U+0067U+0041U+0064U+0076U+0077U+0036U+006BU+0047U+0062U+0050U+004FU+004FU+004BU+0055U+0071U+0033U+0057U+006DU+004EU+0062U+0030U+0047U+0044U+0043U+005AU+0061U+0070U+0071U+0051U+0077U+0079U+0055U+004BU+004BU+004DU+0048U+006DU+004EU+0049U+0055U+004DU+0056U+004DU+0041U+004FU+0079U+0056U+0066U+004BU+0065U+0045U+004DU+004AU+0041U+0036U+004CU+0056U+0069U+0047U+0077U+0079U+0076U+0048U+0056U+004DU+004EU+005AU+0031U+0058U+0057U+004CU+0072U+0030U+0078U+0061U+0066U+004BU+0066U+0045U+0075U+007AU+0034U+0071U+006FU+0048U+0069U+0044U+0079U+0076U+0057U+006FU+006DU+0047U+006AU+004AU+0074U+0038U+0044U+0051U+0064U+0036U+002BU+006AU+0067U+004CU+006BU+003D"
	A    = un(a)
	B    = un(b)
	C    = un(c)
	D    = un(d)
	f, _ = hex.DecodeString(AesDecrypt(A, key))
	g, _ = hex.DecodeString(AesDecrypt(B, key))
	h, _ = hex.DecodeString(AesDecrypt(C, key))
	i, _ = hex.DecodeString(AesDecrypt(D, key))
	//j, _ = hex.DecodeString(AesDecrypt(E, key))
)

func un(cc string) string {
	var result string
	for i := 0; i < len(cc); i += 6 {
		co := cc[i+2 : i+6]
		r, _ := strconv.ParseInt(co, 16, 32)
		result += string(r)
	}
	return result
}

func MS17010Scan(ip string) bool {
	conn, err := WrapperTcpWithTimeout("tcp", ip+":445", time.Duration(5)*time.Second)
	if err != nil {
		return false
	}
	defer conn.Close()
	err = conn.SetDeadline(time.Now().Add(5 * time.Second))
	if err != nil {
		return false
	}
	_, err = conn.Write(f)
	if err != nil {
		return false
	}
	reply := make([]byte, 1024)
	if n, err := conn.Read(reply); err != nil || n < 36 {
		return false
	}

	if binary.LittleEndian.Uint32(reply[9:13]) != 0 {
		return false
	}

	_, err = conn.Write(g)
	if err != nil {
		return false
	}
	n, err := conn.Read(reply)
	if err != nil || n < 36 {
		return false
	}

	if binary.LittleEndian.Uint32(reply[9:13]) != 0 {
		return false
	}

	var os string
	sessionSetupResponse := reply[36:n]
	if wordCount := sessionSetupResponse[0]; wordCount != 0 {
		byteCount := binary.LittleEndian.Uint16(sessionSetupResponse[7:9])
		if n != int(byteCount)+45 {
			return false
		} else {
			for i := 10; i < len(sessionSetupResponse)-1; i++ {
				if sessionSetupResponse[i] == 0 && sessionSetupResponse[i+1] == 0 {
					os = string(sessionSetupResponse[10:i])
					os = strings.Replace(os, string([]byte{0x00}), "", -1)
					break
				}
			}
		}

	}
	userID := reply[32:34]
	h[32] = userID[0]
	h[33] = userID[1]
	_, err = conn.Write(h)
	if err != nil {
		return false
	}
	if n, err := conn.Read(reply); err != nil || n < 36 {
		return false
	}

	treeID := reply[28:30]
	i[28] = treeID[0]
	i[29] = treeID[1]
	i[32] = userID[0]
	i[33] = userID[1]

	_, err = conn.Write(i)
	if err != nil {
		return false
	}
	if n, err := conn.Read(reply); err != nil || n < 36 {
		return false
	}

	if reply[9] == 0x05 && reply[10] == 0x02 && reply[11] == 0x00 && reply[12] == 0xc0 {
		return true
	}
	return false
}

func AesDecrypt(cryted string, key string) string {
	// 转成字节数组
	crytedByte, _ := base64.StdEncoding.DecodeString(cryted)
	k := []byte(key)
	// 分组秘钥
	block, _ := aes.NewCipher(k)
	// 获取秘钥块的长度
	blockSize := block.BlockSize()
	// 加密模式
	blockMode := cipher.NewCBCDecrypter(block, k[:blockSize])
	// 创建数组
	orig := make([]byte, len(crytedByte))
	// 解密
	blockMode.CryptBlocks(orig, crytedByte)
	// 去补全码
	orig = PKCS7UnPadding(orig)
	return string(orig)
}

// PKCS7UnPadding 去码
func PKCS7UnPadding(origData []byte) []byte {
	length := len(origData)
	unpadding := int(origData[length-1])
	return origData[:(length - unpadding)]
}

func WrapperTcpWithTimeout(network, address string, timeout time.Duration) (net.Conn, error) {
	d := &net.Dialer{Timeout: timeout}
	return WrapperTCP(network, address, d)
}

func WrapperTCP(network, address string, forward *net.Dialer) (net.Conn, error) {
	var conn net.Conn

	var err error
	conn, err = forward.Dial(network, address)
	if err != nil {
		return nil, err
	}

	return conn, nil

}
